package com.xjgz.aio.socket.pro.extension.decoder;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * 指定结束标记的解码器
 */
public class DelimiterFrameDecoder implements SmartDecoder {

    private final int reposition;

    /**
     * 存储已解析的数据
     */
    private final List<ByteBuffer> bufferList;

    /**
     * 消息结束标志
     */
    private byte[] endFlag;

    /**
     * 期望本次校验的结束标索引位置
     */
    private int exceptIndex;

    /**
     * 是否解析完成
     */
    private boolean finishRead;

    private int position;

    public DelimiterFrameDecoder(byte[] endFlag, int unitBufferSize) {
        if (endFlag == null || endFlag.length == 0) {
            throw new IllegalArgumentException("end flag must not be empty!");
        }
        if (unitBufferSize < 1) {
            throw new IllegalArgumentException("unit buffer size must greater than zero!");
        }
        this.endFlag = endFlag;
        int p = 0;
        for (int i = 0; i < endFlag.length; i++) {
            if (endFlag[i] != endFlag[0]) {
                p = i - 1;
                break;
            }
        }
        this.reposition = p;
        bufferList = new ArrayList<>();
        bufferList.add(ByteBuffer.allocate(unitBufferSize));
    }

    @Override
    public boolean decode(ByteBuffer byteBuffer) {
        if (finishRead) {
            throw new RuntimeException("delimiter has finish read");
        }
        ByteBuffer preBuffer = bufferList.get(position);

        while (byteBuffer.hasRemaining()) {
            if (!preBuffer.hasRemaining()) {
                preBuffer.flip();
                position++;
                if (position < bufferList.size()) {
                    preBuffer = bufferList.get(position);
                    preBuffer.clear();
                } else {
                    preBuffer = ByteBuffer.allocate(preBuffer.capacity());
                    bufferList.add(preBuffer);
                }
            }
            byte data = byteBuffer.get();
            preBuffer.put(data);
            if (data != endFlag[exceptIndex]) {
                if (exceptIndex != position + 1 || data != endFlag[reposition]) {
                    exceptIndex = endFlag[0] == data ? 1 : 0;
                }
            } else if (++exceptIndex == endFlag.length) {
                preBuffer.flip();
                finishRead = true;
                break;
            }
        }
        return finishRead;
    }

    @Override
    public ByteBuffer getBuffer() {
        if (position == 0) {
            return bufferList.get(position);
        }
        byte[] data = new byte[position * bufferList.get(0).capacity() + bufferList.get(position).limit()];
        int index = 0;
        for (int i = 0; i <= position; i++) {
            ByteBuffer b = bufferList.get(i);
            System.arraycopy(b.array(), b.position(), data, index, b.remaining());
            index += b.remaining();
        }
        return ByteBuffer.wrap(data);
    }

    public void reset() {
        reset(null);
    }

    /**
     * 重置解码器
     */
    public void reset(byte[] endFlag) {
        if (endFlag != null) {
            this.endFlag = endFlag;
        }
        finishRead = false;
        exceptIndex = 0;
        position = 0;
        bufferList.get(position).clear();
    }
}
